import gtk

from xml.sax.saxutils import escape, unescape

from os import listdir, path
import xml.dom.minidom as minidom

categories = ['keywords', 'layout', 'qualifiers', 'shortcuts']

class WidgetOrganizer:
    '''handles propper interacting between widgets'''
    
    def __init__(self, identifier, ancestor=None): 
        self.identifier = identifier
        self.ancestor = ancestor
        self.children = []
        self.Loader = self.getAncestor('MainWindow').Loader
        self.settingOrganizer = self.getAncestor('MainWindow').settingOrganizer
        self.show()
        
    def addChild(self, child, pos=0):
        if pos==-1:
            self.children.append(child)
        else:
            self.children.insert(pos, child)
        
    def getAncestor(self, identifier):
        if identifier==self.identifier or self.ancestor==None:
            return self
        else:
            return self.ancestor.getAncestor(identifier)
        
    def setCategory(self, category):
        for i in self.children:
            i.setCategory(category)


class SettingChanger:
    def __init__(self, settingOrganizer):
        self.mainWindow = MainWindow(settingOrganizer)
        self.mainWindow.setCategory(categories[0])


class MainWindow(WidgetOrganizer, gtk.Window):
    def __init__(self, settingOrganizer):
        self.settingOrganizer = settingOrganizer
        self.Loader = settingOrganizer.Loader
        gtk.Window.__init__(self)
        WidgetOrganizer.__init__(self, 'MainWindow')
        
        self.set_transient_for(settingOrganizer.mainWindow)
        self.resize(600, 400)
        
        self.connect('delete_event', self._event_delete)
        
        self.dirs = self.settingOrganizer.dirs
        
        child = MainVBox(self)
        
        self.add(child)
        self.addChild(child)
        
    def _event_delete(self, *args):
        pass


class MainVBox(WidgetOrganizer, gtk.VBox):
    def __init__(self, ancestor):
        gtk.VBox.__init__(self)
        WidgetOrganizer.__init__(self, 'MainVBox', ancestor)
        
        children = [[ChooseBar(self), False],
                    [Settings(self), True],
                    [ActionBar(self), False]]
        
        for child, expand in children:
            self.pack_start(child, expand=expand)
            self.addChild(child)
            
            
class ChooseBar(WidgetOrganizer, gtk.HBox):
    def __init__(self, ancestor):
        gtk.HBox.__init__(self)
        WidgetOrganizer.__init__(self, 'ChooseBar', ancestor)
        
        for c in categories:
            b = gtk.Button(c)
            b.show()
            def changeCategory(button, category):
                self.getAncestor('MainWindow').setCategory(category)
            b.connect('clicked', changeCategory, c)
            b.set_relief(gtk.RELIEF_NONE)
            b.set_focus_on_click(False)    
            self.pack_start(b, expand=False, fill=False, padding=1)

class ActionBar(WidgetOrganizer, gtk.HBox):
    def __init__(self, ancestor):
        gtk.HBox.__init__(self)
        WidgetOrganizer.__init__(self, 'ActionBar', ancestor)
        
        stocks = [gtk.STOCK_HELP, gtk.STOCK_CLOSE]
        buttons = [gtk.Button(stock=s) for s in stocks]
        
        for b in buttons:
            b.show()
            b.set_focus_on_click(False)
            self.pack_start(b, expand=False, fill=False)
            
        emptyLabel = gtk.Label('')
        emptyLabel.show()
        self.pack_start(emptyLabel)
        self.reorder_child(emptyLabel, 1)

class Settings(WidgetOrganizer, gtk.Frame):
    def __init__(self, ancestor):
        gtk.Frame.__init__(self)
        WidgetOrganizer.__init__(self, 'Settings', ancestor)
        
        child = SettingsVBox(self)
        self.add(child)
        self.addChild(child)
        
class SettingsVBox(WidgetOrganizer, gtk.VBox):
    def __init__(self, ancestor):
        gtk.VBox.__init__(self)
        WidgetOrganizer.__init__(self, 'SettingsVBox', ancestor)
        
        children = [[SettingsFileChooser(self), False],
                    [SettingsFileViewer(self), True]]
        
        for child, expand in children:
            self.pack_start(child, expand=expand)
            self.addChild(child)
            
    def showFile(self, path):
        self.children[0].showFile(path)
        
    def applyFile(self):
        self.children[0].applyFile()
        
    def resetFile(self):
        self.children[0].resetFile()
        
        
class SettingsFileChooser(WidgetOrganizer, gtk.HBox):
    def __init__(self, ancestor):
        gtk.HBox.__init__(self)
        WidgetOrganizer.__init__(self, 'SettingsFileChooser', ancestor)
        
        self.files = []
        
        self.ComboBox = gtk.combo_box_new_text()
        self.ComboBox.show()
        
        self.ComboBox.connect('changed', self._event_chooseFile)
        
        self.setDefaultButton = gtk.Button('set as Default')
        self.setDefaultButton.show()
        
        self.setDefaultButton.connect('clicked', self._event_setDefault)
        
        self.pack_start(self.ComboBox)
        self.pack_start(self.setDefaultButton, expand=False) 
        
    def _event_chooseFile(self, combobox):
        path = self.dir + combobox.get_active_text()
        self.ancestor.showFile(path)
        
    def _event_setDefault(self, button):
        self.Loader.setDefault(self.dir, self.ComboBox.get_active_text())
        
    def setCategory(self, category):
        for i in self.files:
            self.ComboBox.remove_text(0)
            
        self.dir = self.getAncestor('MainWindow').dirs[category]
        self.files = self.Loader.getFiles(self.dir)
        for i in self.files:
            self.ComboBox.append_text(i)
        self.ComboBox.set_active(0)
        
class SettingsFileViewer(WidgetOrganizer, gtk.VBox):
    def __init__(self, ancestor):
        gtk.VBox.__init__(self)
        WidgetOrganizer.__init__(self, 'SettingsFileViewer', ancestor)
        
        display = Display(self)
        controlBar = ControlBar(self)
        
        self.pack_start(display, expand=True)
        self.pack_start(controlBar, expand=False)
        
        self.addChild(controlBar)
        self.addChild(display)
        

    def showFile(self, path):
        self.children[0].showFile(path)
        
    def resetFile(self):
        self.children[0].resetFile()
        
    def applyFile(self):
        self.children[0].applyFile()
    
    def setCategory(self, category):
        self.children[0].setCategory(category)


class ControlBar(WidgetOrganizer, gtk.HBox):
    def __init__(self, ancestor):
        gtk.HBox.__init__(self)
        WidgetOrganizer.__init__(self, 'SettingsFileViewer', ancestor)
        
        empty = gtk.Label()
        resetButton = gtk.Button(stock=gtk.STOCK_REVERT_TO_SAVED)
        applyButton = gtk.Button(stock=gtk.STOCK_APPLY)
        
        resetButton.connect('clicked', self._event_reset)
        applyButton.connect('clicked', self._event_apply)
        
        empty.show()
        resetButton.show()
        applyButton.show()
        
        self.pack_start(empty, expand=True)
        self.pack_start(resetButton, expand=False)
        self.pack_start(applyButton, expand=False)
 
    def _event_reset(self, button):
        self.getAncestor('SettingsVBox').resetFile()
        
    def _event_apply(self, button):
        self.getAncestor('SettingsVBox').applyFile()
        self.settingOrganizer.load()

class Display(WidgetOrganizer, gtk.ScrolledWindow):
    def __init__(self, ancestor):
        gtk.ScrolledWindow.__init__(self)
        WidgetOrganizer.__init__(self, 'Worksheet', ancestor)
        
        self.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
    
    def showFile(self, path):
        self.children[0].showFile(path)
        
    def resetFile(self):
        self.children[0].resetFile()
        
    def applyFile(self):
        self.children[0].applyFile()
    
    def destroyChild(self):
        if self.children:
            self.children[0].destroy()
            self.children = []
    
    def setCategory(self, category):
        self.destroyChild()
        exec 'child = Display_'+category+'(self)'
        self.add(child)
        self.addChild(child)
        
    
       
class Display_keywords(WidgetOrganizer, gtk.TreeView):
    def __init__(self, ancestor):
        self.model = gtk.TreeStore(str, str)
        
        gtk.TreeView.__init__(self, self.model)
        WidgetOrganizer.__init__(self, 'DisplayKeywords', ancestor)
        
        self.set_rules_hint(True)
        
        self.DOM = None
        self.path = ''
        
        renderer1 = gtk.CellRendererText()
        renderer2 = gtk.CellRendererText()
        renderer2.set_property('editable', True)
        renderer2.connect('edited', self._event_edited)
        
        column1 = gtk.TreeViewColumn('Keyword', renderer1, text=0)
        column2 = gtk.TreeViewColumn('Identifier', renderer2, text=1)
        
        self.append_column(column1)
        self.append_column(column2)
        
    def _event_edited(self, renderer, path, newText):
        i = path.split(':')
        iter = self.keyLink[int(i[0])][int(i[1])][0]
        node = self.keyLink[int(i[0])][int(i[1])][1]
        self.model.set_value(iter, 1, newText)
        node.data = newText
        
        
    def showFile(self, path):
        self.path = path
        
        self.model = gtk.TreeStore(str, str)
        self.set_model(self.model)
        
        self.DOM = self.Loader.getDOM(path)
        mainElement = self.DOM.documentElement
        self.keyLink = []
        for keyType in mainElement.childNodes:
            if keyType.nodeType != keyType.ELEMENT_NODE:
                continue
            keytypeLink = []
            self.keyLink.append(keytypeLink)
            
            iter = self.model.append(None, [keyType.localName, ''])
            for key in keyType.childNodes:
                if keyType.nodeType != keyType.ELEMENT_NODE:
                    continue
                identifier = ''
                e = None
                keyword = key.localName
                for entry in key.childNodes:
                    if entry.nodeType is not entry.TEXT_NODE:
                        entry.unlink()
                        continue
                    buf = unescape(entry.data).strip(' \t\n')
                    if buf:
                        identifier = buf
                        e = entry
                    entry.data = identifier
                if keyword:
                    i = self.model.append(iter, [keyword, identifier])
                    keytypeLink.append([i, e])
    
    def applyFile(self):
        if self.DOM and self.path:
            self.Loader.setDOM(self.DOM, self.path)
    
    def resetFile(self):
        if self.DOM:
            self.showFile(self.path)


class Display_shortcuts(WidgetOrganizer, gtk.TreeView):
    modifiers = ['ctrl', 'alt', 'shift']
    
    def __init__(self, ancestor):
        self.model = gtk.ListStore(str, str)
        gtk.TreeView.__init__(self, self.model)
        WidgetOrganizer.__init__(self, 'DisplayShortcuts', ancestor)
        
        self.DOM = None
        self.path = ''
        
        self.set_rules_hint(True)
        
        self.shortcuts = []
        self.changedShortcut = None
        
        self.connect('cursor-changed', self._event_changeKey)
        self.connect('key-press-event', self._event_newKey)
        self.connect('focus-out-event', self.abortChanging)
        
        renderer = gtk.CellRendererText()
        
        column1 = gtk.TreeViewColumn('Action', renderer, text=0)
        column2 = gtk.TreeViewColumn('Shortcut', renderer, text=1)
        
        self.append_column(column1)
        self.append_column(column2)
        
    def showFile(self, path):
        self.path = path
        self.shortcuts = []
        self.changedShortcuts = None
        
        self.model = gtk.ListStore(str, str)
        self.set_model(self.model)
        
        self.DOM = self.Loader.getDOM(path)
        mainElement = self.DOM.documentElement
        
        for element in mainElement.childNodes:
            if element.nodeType != element.ELEMENT_NODE:
                continue
            label = ''
            name = ''
            node = None
            for node in element.childNodes:
                if node.nodeType is not node.TEXT_NODE:
                    element.unlink()
                    continue
                buf = unescape(node.data).strip(' \t\n')
                if buf:
                    keyval, modifier = gtk.accelerator_parse(buf)
                    label = gtk.accelerator_get_label(keyval, modifier)
                    name = gtk.accelerator_name(keyval, modifier)
                    node.data = name
            if not node:
                node = minidom.Document().createTextNode('')
                element.appendChild(node)
            iter = self.model.append([element.getAttribute('description'), label])
            self.shortcuts.append([iter, node, label])
            
            
    def _event_changeKey(self, treeview):
        self.abortChanging()
        self.changedShortcut = treeview.get_cursor()[0][0]
        self.model.set_value(self.shortcuts[self.changedShortcut][0], 1, 'new shortcut')
        
    def _event_newKey(self, widget, event):
        if self.changedShortcut==None:
            return False
        masks = gtk.accelerator_get_default_mod_mask()
        
        if not event.state & masks:
            return True
        
        name = gtk.accelerator_name(event.keyval, event.state & masks)
        label = gtk.accelerator_get_label(event.keyval, event.state & masks)
        self.shortcuts[self.changedShortcut][2] = label
        self.shortcuts[self.changedShortcut][1].data = name
        self.abortChanging()
        return True
    
    def abortChanging(self, *args):
        if self.changedShortcut!=None:
            self.model.set_value(self.shortcuts[self.changedShortcut][0], 1, self.shortcuts[self.changedShortcut][2])
            self.changedShortcut = None
            
    def applyFile(self):
        if self.DOM and self.path:
            self.Loader.setDOM(self.DOM, self.path)
            
    def resetFile(self):
        if self.DOM:
            self.showFile(self.path)
            

class Display_layout(WidgetOrganizer, gtk.TreeView):
    def __init__(self, ancestor):
        gtk.TreeView.__init__(self)
        WidgetOrganizer.__init__(self, 'DisplayLayout', ancestor)
        
    def showFile(self, path):
        pass
    
    def applyFile(self):
        pass
    
    def resetFile(self):
        pass

class Display_qualifiers(WidgetOrganizer, gtk.TreeView):
    def __init__(self, ancestor):
        gtk.TreeView.__init__(self)
        WidgetOrganizer.__init__(self, 'DisplayQualifiers', ancestor)
        
    def showFile(self, path):
        pass
    
    def applyFile(self):
        pass
    
    def resetFile(self):
        pass

    